﻿using System;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using K9Nano.LayIM.Models;
using K9Nano.LayIM.Stores;
using K9Nano.LayIM.Utils;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.StaticFiles;
using Microsoft.Extensions.Options;

namespace K9Nano.LayIM.Controllers
{
    [Area("IM")]
    [ApiController]
    [Route("api/im/file")]
    public class FileController : Controller
    {
        private readonly IFileStore _fileStore;
        private readonly LayIMOptions _options;
        private readonly long _maxImageLength;
        private readonly IContentTypeProvider _contentTypeProvider;

        public FileController(IFileStore fileStore, IOptions<LayIMOptions> optionsAccessor)
        {
            _fileStore = fileStore;
            _contentTypeProvider = new FileExtensionContentTypeProvider();
            _options = optionsAccessor.Value;
            _maxImageLength = _options.GetMaxImageLength();
        }

        [Authorize(Policy = Constants.File_Upload_Authorize_Policy)]
        [HttpPost("image")]
        public async Task<IActionResult> Image([FromForm] IFormFile file)
        {
            if (file == null || file.Length == 0)
            {
                return BadRequest("No file found");
            }

            var fileName = file.FileName;
            if (string.IsNullOrEmpty(fileName))
            {
                return BadRequest("FileName can not be null");
            }

            var ext = Path.GetExtension(fileName);

            if (string.IsNullOrEmpty(ext))
            {
                return BadRequest("File extension can not be null");
            }

            if (_options.AllowedImageExtensions.All(x => !x.Equals(ext, StringComparison.InvariantCultureIgnoreCase)))
            {
                return BadRequest("File extension not supported");
            }

            if (file.Length > _maxImageLength)
            {
                return BadRequest("File is too large");
            }

            var result = await _fileStore.SaveAsync(fileName, file.OpenReadStream(), HttpContext.RequestAborted);

            var response = new LayIMUploadResponse
            {
                name = fileName,
                src = Request.GetAbsoluteUrl($"/api/im/file/{result}")
            };

            return Json(new LayIMApiResponse<LayIMUploadResponse>(response));
        }

        [Authorize(Policy = Constants.File_Access_Authorize_Policy)]
        [HttpGet("{id}")]
        public async Task<IActionResult> Get(string id)
        {
            var file = await _fileStore.GetAsync(id, HttpContext.RequestAborted);
            if (file == null)
            {
                // or return a default 404 image
                return NotFound();
            }

            _contentTypeProvider.TryGetContentType(file.Name, out var contentType);

            return File(file.Stream, contentType);
        }

        [Authorize(Policy = Constants.File_Access_Authorize_Policy)]
        [HttpGet("download/{id}")]
        public async Task<IActionResult> Download(string id)
        {
            var file = await _fileStore.GetAsync(id, HttpContext.RequestAborted);
            if (file == null)
            {
                // or return a default 404 image
                return NotFound();
            }

            _contentTypeProvider.TryGetContentType(file.Name, out var contentType);

            return File(file.Stream, contentType, file.Name);
        }
    }
}